import { is_array, is_object } from "../util";

export default class OkayProxy {
    constructor(data) {
        this.okays = new Set()
        this.data = data
        this.proxy(this.data)
        this.data.proxy = this
    }

    /**
     * 代理data参数
     * @param data
     */
    proxy (obj, path) {
        let that = this
        Object.keys(obj).forEach((key) =>{
            let val = obj[key];
            let path0 = (path == "" || path == undefined)?key:(path + "." + key);
            if(is_object(val)){
                Object.defineProperty(obj, key, {
                    get: function () {
                        return val;
                    },
                    set: function (value) {
                        val = value;
                        if(is_object(val) || is_array(val)){
                            that.proxy(val,path0)
                        }
                        for(let okay of that.okays) {
                            okay.publish(path0)
                        }
                    }
                })
                that.proxy(val, path0)
            }else if(is_array(val)){
                let arrayProto = Array.prototype
                let arrayMethods = Object.create(arrayProto)
                let newArrProto = [];
                [
                    'push',
                    'pop',
                    'shift',
                    'unshift',
                    'splice',
                    'sort',
                    'reverse'
                ].forEach(function(method){
                    let original = arrayMethods[method]
                    newArrProto[method] = function mutator() {
                        original.apply(this, arguments)
                        if (method == 'push') {
                            if(is_object(arguments[0]) && is_array(arguments[0])) {
                                that.proxy(arguments[0], path0 + '.' + (this.length - 1))
                            }
                        } else if(method == 'unshift') {
                            for(let i = arguments.length - 1; i >=0;i--) {
                                if(is_object(arguments[i]) && is_array(arguments[i])) {
                                    that.proxy(arguments[i], path0 + '.' + i)
                                }
                            }
                        }
                        let __post = {method:method,arguments:arguments}
                        for(let okay of that.okays) {
                            okay.publish(path0, __post)
                            okay.publish(path0 + '.length',__post)
                        }
                    }
                })
                val.__proto__  = newArrProto
                that.proxy(val, path0)
            }else{
                console.log(obj)
                Object.defineProperty(obj, key, {
                    get: function (){
                        return val;
                    },
                    set: function (value) {
                        val = value;
                        if(key != 'proxy' && key != 'proxyed'){
                            for(let okay of that.okays) {
                                okay.publish(path0)
                            }
                        }
                    }
                })
            }
        })

    }

}